package com.victualler.core.common.utils;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.*;


import com.victualler.core.common.dto.QueryDto;
import com.victualler.core.common.enums.QueryConditionEnum;
import org.springframework.data.jpa.domain.Specification;


 
/**
 * 
 * @author Administrator
 *
 */
public class SpecificationUtil {
  /**
   * 根据连接条件对象反馈Specification 为herbinate提供对应的动态条件查询
   * @param queryDtoList
   * @return
   */
  public static <T>Specification<T>  getSpecification(List<QueryDto> queryDtoList){
	  Specification<T>  specification = new Specification<T>() { 
		@Override
		public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
			List<Predicate> predicateList= new ArrayList<>(); 
 			List<Order> orderList = new ArrayList<>();
			for (QueryDto queryDto : queryDtoList) {
				//加入排序
				if(queryDto.getCompare().equals(QueryConditionEnum.DESC)){
					orderList.add(cb.desc(root.get(queryDto.getFieldName())));
				}else if(queryDto.getCompare().equals(QueryConditionEnum.ASC)){
					orderList.add(cb.asc(root.get(queryDto.getFieldName())));
				}
				
				//自动跳过空的值
				if(queryDto.getValue() == null || queryDto.getValue().length() == 0){
					continue;
				}
				Predicate predicate = null;
				//匹配连接条件
				if(queryDto.getCompare().equals(QueryConditionEnum.EQ.getKey())){
					predicate = cb.equal(root.get(queryDto.getFieldName()),queryDto.getValue());
				}else if(queryDto.getCompare().equals(QueryConditionEnum.Less.getKey())){
					predicate = cb.lessThan(root.get(queryDto.getFieldName()),queryDto.getValue());
				}else if(queryDto.getCompare().equals(QueryConditionEnum.LessAndEQ.getKey())){
					predicate = cb.lessThanOrEqualTo(root.get(queryDto.getFieldName()),queryDto.getValue());
				}else if(queryDto.getCompare().equals(QueryConditionEnum.Greater.getKey())){
					predicate = cb.greaterThan(root.get(queryDto.getFieldName()),queryDto.getValue());
				}else if(queryDto.getCompare().equals(QueryConditionEnum.GreaterAndEQ.getKey())){
					predicate = cb.greaterThanOrEqualTo(root.get(queryDto.getFieldName()),queryDto.getValue());
				}else if(queryDto.getCompare().equals(QueryConditionEnum.Like.getKey())){
					predicate = cb.like(root.get(queryDto.getFieldName()),"%"+queryDto.getValue()+"%");
				}else if(queryDto.getCompare().equals(QueryConditionEnum.StartLike.getKey())){
					predicate = cb.greaterThanOrEqualTo(root.get(queryDto.getFieldName()),queryDto.getValue()+"%");
				}else if(queryDto.getCompare().equals(QueryConditionEnum.endLike.getKey())){
					predicate = cb.greaterThanOrEqualTo(root.get(queryDto.getFieldName()),"%"+queryDto.getValue());
				}else if(queryDto.getCompare().equals(QueryConditionEnum.idIn.getKey())){
					predicate = SpecificationUtil.getIdInChildParnetId(root,query,cb,queryDto);
				}

				if(predicate != null){ 
					predicateList.add(predicate);
				} 
			} 
			query.where(predicateList.toArray(new Predicate[predicateList.size()]));
			query.orderBy(orderList);
			return  query.getRestriction();
		}
	  };
	  return specification;
  }


  private static Predicate  getIdInChildParnetId(Root root, CriteriaQuery<?> query, CriteriaBuilder cb,QueryDto queryDto){
	  try {
		  Subquery<?>   subquery = query.subquery(Class.forName(queryDto.getChildClassName()));
		  Root<?> subRoot = subquery.from(Class.forName(queryDto.getChildClassName()));
		  subquery.select(subRoot.get("parentId"));
		  subquery.where(cb.equal(subRoot.get(queryDto.getFieldName()), queryDto.getValue()));
		  return cb.in(root.get("id")).value(subquery) ;
	  } catch (ClassNotFoundException e) {
		  e.printStackTrace();
		  return null;
	  }
  }
}
